package org.apache.derby.drda;

import com.czy.consts.Const;
import com.czy.util.StringUtil;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.derby.iapi.tools.i18n.LocalizedResource;
import org.apache.derby.shared.common.reference.Property;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Objects;
import java.util.Properties;
import java.util.StringTokenizer;


/**
 * @author ex_chenzy59
 * @since 2025/3/5
 *
 */
@Slf4j
public class NetServlet extends HttpServlet {
    private final static int MAX_CONNECT_TRYS = 20;
    /*todo*/
    private final static String SERVLET_PROP_MESSAGES = "org.apache.derby.loc.drda.servlet";
    private final static int PORT_DEFAULT = 1527;
    private final static String HOST_DEFAULT = "localhost";
    private final static String SERVLET_ADDRESS = "derbynet";
    private final static String[] knownLang =
            {"cs", "en", "es", "de_DE", "fr", "hu", "it", "ja_JP", "ko_KR", "pl", "pt_BR", "ru", "zh_CN", "zh_TW"};
    private final static int NOT_GIVEN = -2;
    private final static int INVALID = -3;
    private String host = HOST_DEFAULT;
    private int portNumber = PORT_DEFAULT;
    private volatile String tracingDirectory;
    private volatile boolean logStatus = false;  /* Logging off */
    private volatile boolean traceStatus = false;   /* Tracing off */
    private NetworkServerControl server;

    /**
     *
     */
    private static boolean isServerStarted(NetworkServerControl server, int ntries) {
        for (int i = 1; i <= ntries; i++) {
            try {
                Thread.sleep(500);
                server.ping();
                return true;
            } catch (Exception e) {
                if (i == ntries) {
                    return false;
                }
            }
        }
        return false;
    }

    /**
     Initialize the servlet.
     Configuration parameters: portNumber,host,traceDirectory,startNetworkServerOnInit
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        try {
            StringUtil.getInt(config.getInitParameter("portNumber"))
                    .filter(i -> i > 0)
                    .ifPresent(i -> portNumber = i);
            var hostName = config.getInitParameter("host");
            if (hostName != null) {
                host = hostName;
            }
            tracingDirectory = config.getInitParameter("tracingDirectory");
            if (tracingDirectory == null) {
                tracingDirectory = "";
            }
            /*获取服务对象*/
            if (server == null) {
                server = new NetworkServerControl(InetAddress.getByName(host), portNumber);
                if (StringUtil.isBlank(tracingDirectory)) {
                    server.setTraceDirectory(tracingDirectory);
                }
            }
            if (StringUtil.getBoolean(config.getInitParameter("startNetworkServerOnInit"), false)
                    && !isServerStarted(server, 1)) {
                /*配置startNetworkServerOnInit=true且服务未启动时,启动服务*/
                runServer(new LocalizedResource(SERVLET_PROP_MESSAGES), null, null);
            }
        } catch (Exception e) {
            log.error("初始化异常:", e);
            System.exit(-1);
        }
    }

    @Override
    public synchronized void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String logOnMessage;
        String logOffMessage;
        String traceOnMessage;
        String traceOffMessage;
        String traceOnOffMessage;
        String stopMessage;
        String returnMessage;
        String traceSessionMessage;
        String traceDirMessage;
        String netParamMessage;

        String[] locale = new String[1];

        LocalizedResource langUtil = getCurrentAppUI(request, locale);
        response.setContentType("text/html; charset=UTF-8");

        //prevent caching of the servlet since contents can change - beetle 4649
        response.setHeader("Cache-Control", "no-cache,no-store");

        String formHeader = STR."<form enctype='multipart/form-data; charset=UTF-8' action='\{request.getContextPath() + request.getServletPath()}'>";

        var out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), Const.charset), true);

        //inialize messages
        logOnMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_LogOn"));
        logOffMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_LogOff"));
        traceOnMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_TraceOn"));
        traceOffMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_TraceOff"));
        final var startMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_Start"));
        stopMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_Stop"));
        traceSessionMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_TraceSessButton"));
        traceOnOffMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_TraceOnOff"));
        returnMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_Return"));
        traceDirMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_TraceDir"));
        netParamMessage = escapeSingleQuotes(langUtil.getTextMessage("SRV_NetParam"));
        printBanner(langUtil, out);

        server.setClientLocale(locale[0]);
        String form = getParam(request, "form");
        String doAction = getParam(request, "doaction");
        // if doAction is set, use it to determine form
        if (doAction != null) {
            form = doAction.equals(traceOnOffMessage) ? traceSessionMessage : doAction;
        }
        // if no form, determine form based on server status
        boolean serverStatus = getServerStatus();
        if (form == null || form.equals(returnMessage)) {
            form = serverStatus ? startMessage : stopMessage;
        } else if (form.equals(startMessage)) {
            if (!serverStatus) {
                runServer(langUtil, returnMessage, out);
            }
        } else if (form.equals(stopMessage)) {
            if (serverStatus) {
                shutdownServer(langUtil, returnMessage, out);
            }
            setDefaults();
        }
        out.println(formHeader);

        form = escapeSingleQuotes(form);
        doAction = escapeSingleQuotes(doAction);
        if (form.equals(startMessage)) {
            String logButton = getParam(request, "logform");
            String traceButton = getTrace(request);

            if (Objects.equals(logButton, logOnMessage)) {
                if (logging(langUtil, true, returnMessage, out)){
                    logStatus = true;
                }
            }
            if (Objects.equals(logButton, logOffMessage)) {
                if (logging(langUtil, false, returnMessage, out)){
                    logStatus = false;
                }
            }
            if (Objects.equals(traceButton, traceOnMessage)) {
                 if (traceAll(langUtil, true, returnMessage, out)){
                     traceStatus=true;
                 }
            }
            if (Objects.equals(traceButton, traceOffMessage)) {
                if (traceAll(langUtil, false, returnMessage, out)){
                    traceStatus = false;
                }
            }
            displayCurrentStatus(langUtil, returnMessage, out);
            out.println(STR."<h4>\{langUtil.getTextMessage("SRV_StopButton")}</h4>");
            out.println(STR."<INPUT type=submit name=form value='\{stopMessage}'>");
            out.println(STR."<h4>\{langUtil.getTextMessage("SRV_LogButton2")}</h4>");
            if (logStatus) {
                out.println(STR."<INPUT type=submit name=logform value='\{logOffMessage}'>");
            } else {
                out.println(STR."<INPUT type=submit name=logform value='\{logOnMessage}'>");
            }
            out.println(STR."<h4>\{langUtil.getTextMessage("SRV_TraceButton2")}</h4>");
            if (traceStatus) {
                out.println(STR."<INPUT type=submit name=traceform value='\{traceOffMessage}'>");
            } else {
                out.println(STR."<INPUT type=submit name=traceform value='\{traceOnMessage}'>");
            }
            out.println(STR."<h4>\{langUtil.getTextMessage("SRV_TraceSession")}</h4>");
            out.println(STR."<INPUT type=submit name=form value='\{traceSessionMessage}'>");
            out.println(STR."<h4>\{langUtil.getTextMessage("SRV_TraceDirButton")}</h4>");
            out.println(STR."<INPUT type=submit name=form value='\{traceDirMessage}'>");
            out.println(STR."<h4>\{langUtil.getTextMessage("SRV_ThreadButton")}</h4>");
            out.println(STR."<INPUT type=submit name=form value='\{netParamMessage}'>");
        } else if (form.equals(stopMessage)) {

            printAsContentHeader(langUtil.getTextMessage("SRV_NotStarted"), out);
            String logButton = getParam(request, "logform");
            String traceButton = getTrace(request);
            if (Objects.equals(logButton, logOnMessage))
                logStatus = true;
            if (Objects.equals(logButton,logOffMessage))
                logStatus = false;
            if (Objects.equals(traceButton,traceOnMessage))
                traceStatus = true;
            if (Objects.equals(traceButton,traceOffMessage))
                traceStatus = false;
            if (logStatus) {
                out.println(STR."<h4>\{langUtil.getTextMessage("SRV_LogOffButton")}</h4>");
                out.println(STR."<INPUT type=submit name=logform value='\{logOffMessage}'>");
            } else {
                out.println(STR."<h4>\{langUtil.getTextMessage("SRV_LogOnButton")}</h4>");
                out.println(STR."<INPUT type=submit name=logform value='\{logOnMessage}'>");
            }
            if (traceStatus) {
                out.println(STR."<h4>\{langUtil.getTextMessage("SRV_TraceOffButton")}</h4>");
                out.println(STR."<INPUT type=submit name=traceform value='\{traceOffMessage}'>");
            } else {
                out.println(STR."<h4>\{langUtil.getTextMessage("SRV_TraceOnButton")}</h4>");
                out.println(STR."<INPUT type=submit name=traceform value='\{traceOnMessage}'>");
            }
            out.println(STR."<h4>\{langUtil.getTextMessage("SRV_StartButton")}</h4>");
            out.println(STR."<INPUT type=submit name=form value='\{startMessage}'>");
        } else if (form.equals(traceSessionMessage)) {
            if (doAction != null) {
                if (doAction.equals(traceOnOffMessage)) {
                    String sessionid = request.getParameter("sessionid");
                    Integer session;
                    try {
                        session = Integer.valueOf(sessionid);
                    } catch (NumberFormatException nfe) {
                        printErrorForm(langUtil
                                , langUtil.getTextMessage("SRV_InvalidVal",sessionid, langUtil.getTextMessage("SRV_SessionID"))
                                ,returnMessage, out);
                        return;
                    }
                    Properties p;
                    try {
                        p = server.getCurrentProperties();
                    } catch (Exception e) {
                        printErrorForm(langUtil, e, returnMessage, out);
                        return;
                    }
                    // if it's on, turn it off, if its off, turn it on
                    boolean val;
                    val = p.getProperty(Property.DRDA_PROP_TRACE + sessionid) == null;
                    if (traceSession(langUtil, val, session.intValue(),
                            returnMessage, out)) {
                        out.println(STR."<h4>\{langUtil.getTextMessage(val ? "SRV_StatusTraceNoOn": "SRV_StatusTraceNoOff"
                                ,session.toString())}</h4>");
                    } else
                        return;

                }
            }
            printAsContentHeader(langUtil.getTextMessage("SRV_TraceSessButton"), out);
            out.println(STR."<h4>\{getHtmlLabelledMessageInstance(langUtil,"SRV_SessionID", "sessionId")}</h4>");
            out.println("<INPUT type=text name=sessionid size=10 maxlength=10 id='sessionId' value=''>");
            out.println("<h4> </h4>");
            out.println(STR."<INPUT type=submit name=doaction value='\{traceOnOffMessage}'>");
            out.println(STR."<INPUT type=submit name=form value='\{returnMessage}'>");
        } else if (form.equals(traceDirMessage)) {
            boolean set = false;
            String traceDirectory = null;
            printAsContentHeader(traceDirMessage, out);
            if (doAction != null) {
                if (doAction.equals(traceDirMessage)) {
                    traceDirectory = getParam(request, "tracedirectory");
                    if (traceDirectory(langUtil, traceDirectory,returnMessage, out))
                        set = true;
                    else
                        return;
                }
            }
            if (set) {
                out.println(STR."<h2>\{langUtil.getTextMessage("SRV_TraceDirDone",escapeHTML(traceDirectory))}</h2>");
                out.println(STR."<INPUT type=submit name=form value='\{returnMessage}'>");
            } else {
                out.println(STR."<h4>\{getHtmlLabelledMessageInstance(langUtil,"SRV_TraceDir", "tracedir")}</h4>");
                out.println(STR."<INPUT type=text name=tracedirectory size=60 maxlength=256 id='tracedir' value='\{escapeHTML(tracingDirectory)}'>");
                out.println("<h4> </h4>");
                out.println(STR."<INPUT type=submit name=doaction value='\{traceDirMessage}'>");
                out.println(STR."<INPUT type=submit name=form value='\{returnMessage}'>");
            }
        } else if (form.equals(netParamMessage)) {
            int maxThreads;
            int timeSlice;
            String maxName = langUtil.getTextMessage("SRV_NewMaxThreads");
            String sliceName = langUtil.getTextMessage("SRV_NewTimeSlice");
            try {
                Properties p = server.getCurrentProperties();
                String val = p.getProperty(Property.DRDA_PROP_MAXTHREADS);
                maxThreads = Integer.parseInt(val);
                val = p.getProperty(Property.DRDA_PROP_TIMESLICE);
                timeSlice = Integer.parseInt(val);
            } catch (Exception e) {
                printErrorForm(langUtil, e, returnMessage, out);
                return;
            }
            if (doAction != null && doAction.equals(netParamMessage)) {
                int newMaxThreads = getIntParameter(request, "newmaxthreads",
                        "SRV_NewMaxThreads", langUtil, returnMessage, out);
                int newTimeSlice = (newMaxThreads == INVALID) ? NOT_GIVEN :
                        getIntParameter(request, "newtimeslice", "SRV_NewTimeSlice", langUtil,
                                returnMessage, out);
                if ((newMaxThreads == INVALID) || (newTimeSlice == INVALID))
                    return;
                else if (!(newMaxThreads == NOT_GIVEN && newTimeSlice == NOT_GIVEN)) {
                    if (newMaxThreads != NOT_GIVEN)
                        maxThreads = newMaxThreads;
                    if (newTimeSlice != NOT_GIVEN)
                        timeSlice = newTimeSlice;
                    if (!setNetParam(langUtil, maxThreads, timeSlice,
                            returnMessage, out))
                        return;
                }
            }

            out.println(formHeader);
            printAsContentHeader(netParamMessage, out);
            out.println(STR."<h4>\{langUtil.getTextMessage("SRV_MaxThreads", maxThreads + "</h4>")}");
            out.println(STR."<h4>\{langUtil.getTextMessage("SRV_TimeSlice", timeSlice + "</h4>")}");
            out.println("<h4> </h4>");
            out.println(STR."<h4> <label for='newmaxthreads'>\{maxName}</label> </h4>");
            out.println("<INPUT type=text name=newmaxthreads size=10 maxlength=10 id='newmaxthreads' value=''>");
            out.println(STR."<h4> <label for='newslice'>\{sliceName}</label> </h4>");
            out.println("<INPUT type=text name=newtimeslice size=10 maxlength=10 id='newslice' value=''>");
            out.println("<h4> </h4>");
            out.println(STR."<INPUT type=submit name=doaction value='\{netParamMessage}'>");
            out.println(STR."<INPUT type=submit name=form value='\{returnMessage}'>");
        } else {
            System.out.println(STR."Internal Error: Unknown form, \{form}");
            out.println("Internal Error: Unknown form");
        }

        out.println("</body>");
        out.println("</html>");
    }
    private boolean setNetParam
            (
                    LocalizedResource localUtil,
                    int max,
                    int slice,
                    String returnMessage,
                    PrintWriter out
            ) {
        boolean retval = false;

        try {
            server.setMaxThreads(max);
            server.setTimeSlice(slice);
            retval = true;
        } catch (Exception e) {
            printErrorForm(localUtil, e, returnMessage, out);
        }
        return retval;
    }
    private int getIntParameter
            (
                    HttpServletRequest request,
                    String name,
                    String fieldKey,
                    LocalizedResource localUtil,
                    String returnMessage,
                    PrintWriter out
            ) {
        String val = request.getParameter(name);
        int retval;
        if (val == null || val.equals(""))
            return NOT_GIVEN;
        try {
            retval = Integer.parseInt(val);
        } catch (Exception e) {
            printErrorForm(localUtil, localUtil.getTextMessage("SRV_InvalidVal",
                    val, localUtil.getTextMessage(fieldKey)), returnMessage, out);
            return INVALID;
        }
        if (retval < 0) {
            // negative integers not allowed for the parameters we're getting.
            printErrorForm(localUtil, localUtil.getTextMessage("SRV_InvalidVal",
                    val, localUtil.getTextMessage(fieldKey)), returnMessage, out);
            return INVALID;
        }
        return retval;
    }
    private boolean traceDirectory
            (
                    LocalizedResource localUtil,
                    String traceDirectory,
                    String returnMessage,
                    PrintWriter out
            ) {
        boolean retval = false;

        if ((traceDirectory == null) || traceDirectory.equals("")) {
            printErrorForm(localUtil,
                    localUtil.getTextMessage("SRV_MissingParam",
                            localUtil.getTextMessage("SRV_TraceDir")), returnMessage, out);

            return retval;
        }

        try {
            this.tracingDirectory = traceDirectory;
            server.setTraceDirectory(traceDirectory);
            retval = true;
        } catch (Exception e) {
            printErrorForm(localUtil, e, returnMessage, out);
        }
        return retval;
    }
    private String getHtmlLabelledMessageInstance(LocalizedResource localUtil,
                                                  String key, String id) {

        if (id == null)
            id = "";

        return (STR."<label for='\{id}'>\{localUtil.getTextMessage(key)}</label>");

    }
    private boolean traceSession
            (
                    LocalizedResource localUtil,
                    boolean val,
                    int session,
                    String returnMessage,
                    PrintWriter out
            ) {
        boolean retval = false;
        try {
            server.trace(session, val);
            retval = true;
        } catch (Exception e) {
            printErrorForm(localUtil, e, returnMessage, out);
        }
        return retval;
    }
    private void printErrorForm
            (
                    LocalizedResource localUtil,
                    String msg,
                    String returnMessage,
                    PrintWriter out
            ) {
        printAsContentHeader(localUtil.getTextMessage("SRV_NetworkServerError"), out);
        out.println(
                "<h4>" +
                        localUtil.getTextMessage("SRV_Message", escapeHTML(msg)) +
                        "</h4>");
        out.println("<INPUT type=submit name=form value='" + returnMessage + "'>");
        out.println("</body>");
        out.println("</html>");
    }
    private void displayCurrentStatus
            (
                    LocalizedResource localUtil,
                    String returnMessage,
                    PrintWriter out
            ) {
        try {

            printAsContentHeader(localUtil.getTextMessage("SRV_Started"), out);
            Properties p = server.getCurrentProperties();
            String val = p.getProperty(Property.DRDA_PROP_LOGCONNECTIONS);
            logStatus = val.equals("true");
            if (logStatus)
                out.println("<h4>" + localUtil.getTextMessage("SRV_StatusLogOn") + "</h4>");
            else
                out.println("<h4>" + localUtil.getTextMessage("SRV_StatusLogOff") + "</h4>");
            val = p.getProperty(Property.DRDA_PROP_TRACEALL);
            traceStatus = val.equals("true");
            if (traceStatus)
                out.println("<h4>" + localUtil.getTextMessage("SRV_StatusTraceOn") + "</h4>");
            else
                out.println("<h4>" + localUtil.getTextMessage("SRV_StatusTraceOff") + "</h4>");
            val = p.getProperty(Property.DRDA_PROP_PORTNUMBER);
            out.println("<h4>" + localUtil.getTextMessage("SRV_PortNumber", val) + "</h4>");

        } catch (Exception e) {
            printErrorForm(localUtil, e, returnMessage, out);
        }
    }
    private boolean logging
            (
                    LocalizedResource localUtil,
                    boolean val,
                    String returnMessage,
                    PrintWriter out
            ) {
        boolean retval = false;
        try {
            server.logConnections(val);
            retval = true;
        } catch (Exception e) {
            printErrorForm(localUtil, e, returnMessage, out);
        }
        return retval;
    }

    private boolean getServerStatus() {
        try {

            if (isServerStarted(server, 1))
                return true;
        } catch (Exception e) {
        }
        return false;
    }

    private boolean traceAll(LocalizedResource localUtil, boolean val, String returnMessage, PrintWriter out) {
        try {
            server.trace(val);
            return true;
        } catch (Exception e) {
            printErrorForm(localUtil, e, returnMessage, out);
            return false;
        }
    }

    private String getTrace(HttpServletRequest request) throws IOException {
        return getParam(request, "traceform");
    }

    private String getParam(HttpServletRequest request, String paramName) throws IOException {
        String value = request.getParameter(paramName);
        if (value != null) {
            return new String(value.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
        } else {
            return null;
        }
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    private LocalizedResource getCurrentAppUI(HttpServletRequest request, String[] locale) {
        String acceptLanguage = request.getHeader("Accept-Language");
        var localUtil = new LocalizedResource(SERVLET_PROP_MESSAGES);
        // if no language specified use one set by derby.locale, derby.codeset
        locale[0] = null;
        if (acceptLanguage == null) {
            return localUtil;
        }
        // Use a tokenizer ot separate acceptable languages
        StringTokenizer tokenizer = new StringTokenizer(acceptLanguage, ",");
        while (tokenizer.hasMoreTokens()) {
            //Get the next acceptable language
            String lang = tokenizer.nextToken();
            lang = getLocStringFromLanguage(lang);
            int langindex = translationAvailable(lang);
            // have we found one
            if (langindex != -1) {
                localUtil.init(null, lang, SERVLET_PROP_MESSAGES);
                // locale will be passed to server, server routines will get set appropriately
                locale[0] = lang;
                return localUtil;
            }
        }
        // nothing worked use defaults
        return localUtil;

    }

    private String getLocStringFromLanguage(String lang) {
        int semi;
        // Cut off any q-value that might come after a semi-colon
        if ((semi = lang.indexOf(';')) != -1) {
            lang = lang.substring(0, semi);
        }
        // trim any whitespace and fix the code, as some browsers might send a bad format
        lang = fixLanguageCode(lang.trim());
        return lang;
    }

    private String fixLanguageCode(String lang) {
        int index = lang.indexOf('-');
        if (index != -1) {
            return fixLanguageCode(lang, index);
        }
        index = lang.indexOf('_');
        if (index != -1) {
            return fixLanguageCode(lang, index);
        }
        return lang;
    }

    private String fixLanguageCode(String lang, int index) {
        return STR."\{lang.substring(0, index)}_\{lang.substring(index + 1).toUpperCase(Locale.ENGLISH)}";
    }

    private int translationAvailable(String lang) {
        // assert lang == fixLanguageCode(lang)
        // we don't need to use toUpperCase() anymore, as the lang is already fixed
        for (int i = 0; i < knownLang.length; i++)
            if (knownLang[i].equals(lang))
                return i;
        return -1;
    }

    private void runServer(LocalizedResource localUtil, String returnMessage, PrintWriter out) throws ServletException {
        final Runnable service = new Runnable() {
            public void run() {
                try {
                    //Echo server output to console
                    NetworkServerControl runserver = new
                            NetworkServerControl(InetAddress.getByName(host),
                            portNumber);
                    runserver.start(null);
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage());
                }
            }
        };
        Thread servThread = null;
        try {
            servThread = new Thread(service);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        servThread.start();

        // try to connect to server
        try {
            boolean connectWorked = false;
            int t = 0;
            do {
                t++;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ie) {
                    throw new ServletException(localUtil.getTextMessage("SRV_Interupt"));
                }
                try {
                    if (isServerStarted(server, 1))
                        connectWorked = true;
                } catch (Exception e) {
                } //ignore error we'll just try again

            } while (!connectWorked && t < MAX_CONNECT_TRYS);
            if (t >= MAX_CONNECT_TRYS)
                throw new Exception(localUtil.getTextMessage("SRV_MaxTrys",
                        Integer.toString(MAX_CONNECT_TRYS)));
            // turn logging on if required
            if (logStatus)
                server.logConnections(true);
            // turn tracing on
            if (traceStatus)
                server.trace(true);
        } catch (Exception e) {
            if (out != null)
                printErrorForm(localUtil, e, returnMessage, out);
            else
                throw new ServletException(e.getMessage());
        }
    }

    private boolean shutdownServer
            (
                    LocalizedResource localUtil,
                    String returnMessage,
                    PrintWriter out
            ) {
        boolean retval = false;
        try {
            server.shutdown();
            retval = true;
        } catch (Exception e) {
            printErrorForm(localUtil, e, returnMessage, out);
        }
        return retval;
    }

    private void setDefaults() {
        logStatus = false;
        traceStatus = false;
    }

    private void printErrorForm(LocalizedResource localUtil, Exception e, String returnMessage, PrintWriter out) {
        printAsContentHeader(localUtil.getTextMessage("SRV_NetworkServerError"), out);
        out.println("<h4>" +
                localUtil.getTextMessage(
                        "SRV_Message", escapeHTML(e.getMessage())) + "</h4>");
        out.println("<INPUT type=submit name=form value='" + returnMessage + "'>");
        out.println("</body>");
        out.println("</html>");
    }

    private void printAsContentHeader(String str, PrintWriter out) {
        out.println(STR."<a name=\"navskip\"></a><h2>\{str}</h2>");
    }

    private String escapeHTML(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        // Replaced characters: ; \ / < > " ' = &
        char[] cA = str.toCharArray();
        char[] result = new char[5 * cA.length];
        int j = 0;
        for (int i = 0; i < cA.length; i++) {
            boolean escaped = true; // controls addition of ;
            char c = cA[i];
            switch (c) {
                case ';':
                    result[j++] = '&';
                    result[j++] = '#';
                    result[j++] = '5';
                    result[j++] = '9';
                    break;
                case '\\':
                    result[j++] = '&';
                    result[j++] = '#';
                    result[j++] = '9';
                    result[j++] = '2';
                    break;
                case '/':
                    result[j++] = '&';
                    result[j++] = '#';
                    result[j++] = '4';
                    result[j++] = '7';
                    break;
                case '<':
                    result[j++] = '&';
                    result[j++] = 'l';
                    result[j++] = 't';
                    break;
                case '>':
                    result[j++] = '&';
                    result[j++] = 'g';
                    result[j++] = 't';
                    break;
                case '"':
                    result[j++] = '&';
                    result[j++] = '#';
                    result[j++] = '3';
                    result[j++] = '4';
                    break;
                case '\'':
                    result[j++] = '&';
                    result[j++] = '#';
                    result[j++] = '3';
                    result[j++] = '9';
                    break;
                case '=':
                    result[j++] = '&';
                    result[j++] = '#';
                    result[j++] = '6';
                    result[j++] = '1';
                    break;
                case '&':
                    result[j++] = '&';
                    result[j++] = 'a';
                    result[j++] = 'm';
                    result[j++] = 'p';
                    break;
                default:
                    result[j++] = c;
                    escaped = false;
            }
            if (escaped) {
                result[j++] = ';';
            }
        }
        return String.copyValueOf(result, 0, j);
    }

    private String escapeSingleQuotes(String str) {

        if ((str == null) || (str.indexOf("'") < 0))
            return str;

        char[] cA = str.toCharArray();

        // Worst (and extremely unlikely) case is every
        // character is a single quote, which means the
        // escaped string would need to be 5 times as long.
        char[] result = new char[5 * cA.length];

        int j = 0;
        for (int i = 0; i < cA.length; i++) {

            if (cA[i] == '\'') {
                result[j++] = '&';
                result[j++] = '#';
                result[j++] = '3';
                result[j++] = '9';
                result[j++] = ';';
            } else
                result[j++] = cA[i];

        }

        return new String(result, 0, j);

    }

    private void printBanner(LocalizedResource localUtil, PrintWriter out) {
        out.println("<!DOCTYPE html>");
        out.println("<html>");
        out.println("<head>");
        out.println(STR."<title>\{localUtil.getTextMessage("SRV_Banner")}</title>");
        out.println("</head>");
        out.println("<body>");
        out.println(STR."<a href=\"#navskip\">[ \{localUtil.getTextMessage("SRV_SkipToContent")} ]</a>");
        out.println(STR."  -  <a href=\"\{SERVLET_ADDRESS}\">[ \{localUtil.getTextMessage("SRV_BackToMain")} ]</a>");
        out.println("<hr>");
        out.println(STR."<h1>\{localUtil.getTextMessage("SRV_Banner")}</h1>");
        out.println("<hr>");
    }
}
